package com.rayframework.context.support;


import com.rayframework.beans.MutablePropertyValues;
import com.rayframework.beans.PropertyValue;
import com.rayframework.beans.factory.config.BeanDefinition;
import com.rayframework.beans.factory.support.BeanDefinitionRegistry;
import com.rayframework.beans.factory.xml.XmlBeanDefinitionReader;
import com.rayframework.context.utils.StringUtils;

import java.lang.reflect.Method;


/**
 * IOC容器具体的子实现类，用于加载类路径下的xml格式的配置文件
 * - 在构造方法中，创建BeanDefinitionReader对象。
 * - 在构造方法中，调用refresh()方法，用于进行配置文件加载、创建bean对象并存储到容器中。
 * - 重写父接口中的getBean()方法，并实现【依赖注入操作】。
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2023/11/24 11:42
 **/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    /**
     * 构造方法
     *
     * @param configLocation 配置文件路径
     * @author LiaoYuXing-Ray 2023/11/24 17:02
     **/
    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        // 构建解析器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据bean对象的名称获取bean对象
     *
     * @param name Bean对象的名称
     * @return java.lang.Object Bean对象
     * @author LiaoYuXing-Ray 2023/11/24 17:03
     **/
    @Override
    public Object getBean(String name) throws Exception {
        // 判断对象容器中是否包含指定名称的bean对象，如果包含，直接返回即可，如果不包含，需要自行创建
        Object obj = singletonObjects.get(name);
        if (obj != null) {
            return obj;
        }

        // 通过解析器对象获取注册表对象，获取BeanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 获取bean信息中的className
        String className = beanDefinition.getClassName();
        // 通过反射创建对象
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        /*
         * 进行依赖注入操作 2023/11/24 17:36
         */
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            // 获取name属性值
            String propertyName = propertyValue.getName();
            // 获取value属性
            String value = propertyValue.getValue();
            // 获取ref属性
            String ref = propertyValue.getRef();
            if (ref != null && !"".equals(ref)) {
                // 获取依赖的bean对象 - 递归
                Object bean = getBean(ref);
                // 拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                // 获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (methodName.equals(method.getName())) {
                        // 执行该setter方法
                        method.invoke(beanObj, bean);
                    }
                }
            }

            if (value != null && !"".equals(value)) {
                // 拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                // 获取method对象
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }
        }

        // 在返回beanObj对象之前，将该对象存储到map容器中
        singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if (bean == null) {
            return null;
        }
        // 进行类型强转
        return clazz.cast(bean);
    }

    @Override
    public boolean containsBean(Class<?> clazz) {
        return false;
    }

    @Override
    public boolean containsBean(String beanName) {
        return false;
    }
}
